# import pandas as pd
# import numpy as np
# import matplotlib.pyplot as plt
# from scipy.stats import pearsonr
# import akshare as ak
# import os
# import time
# import tkinter as tk
# from tkinter import ttk, filedialog, messagebox, scrolledtext
# from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
# from matplotlib.figure import Figure
# import threading
# import chardet  # 用于检测文件编码

# # 设置matplotlib支持中文显示
# plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
# plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

# class FuturesAnalysisApp:
#     def __init__(self, root):
#         self.root = root
#         self.root.title("期货净空单与指数涨跌关系分析工具")
#         self.root.geometry("1200x800")
        
#         # 数据存储
#         self.futures_data = None
#         self.index_data = {}
#         self.analysis_results = {}
#         self.contract_types = ['IF', 'IC', 'IM', 'IH']
#         self.index_mapping = {
#             'IF': '沪深300指数',
#             'IC': '中证500指数',
#             'IM': '中证1000指数',
#             'IH': '上证50指数'
#         }
        
#         # 创建界面
#         self.create_widgets()
        
#     def create_widgets(self):
#         # 创建主框架
#         main_frame = ttk.Frame(self.root, padding="10")
#         main_frame.pack(fill=tk.BOTH, expand=True)
        
#         # 左侧控制面板
#         control_frame = ttk.LabelFrame(main_frame, text="控制面板", padding="10")
#         control_frame.pack(side=tk.LEFT, fill=tk.Y, padx=5, pady=5)
        
#         # 文件选择部分
#         ttk.Label(control_frame, text="期货净空单数据文件:").pack(anchor=tk.W, pady=5)
#         self.futures_file_var = tk.StringVar()
#         futures_file_entry = ttk.Entry(control_frame, textvariable=self.futures_file_var, width=40)
#         futures_file_entry.pack(anchor=tk.W, pady=2)
        
#         ttk.Button(control_frame, text="浏览...", command=self.browse_futures_file).pack(anchor=tk.W, pady=2)
        
#         # 日期范围选项
#         date_frame = ttk.LabelFrame(control_frame, text="分析日期范围", padding="5")
#         date_frame.pack(fill=tk.X, pady=5)
        
#         ttk.Label(date_frame, text="开始日期 (YYYY-MM-DD):").grid(row=0, column=0, padx=5, pady=2)
#         self.start_date_var = tk.StringVar()
#         ttk.Entry(date_frame, textvariable=self.start_date_var, width=12).grid(row=0, column=1, padx=5, pady=2)
        
#         ttk.Label(date_frame, text="结束日期 (YYYY-MM-DD):").grid(row=0, column=2, padx=5, pady=2)
#         self.end_date_var = tk.StringVar()
#         ttk.Entry(date_frame, textvariable=self.end_date_var, width=12).grid(row=0, column=3, padx=5, pady=2)
        
#         ttk.Label(date_frame, text="注: 留空则使用数据全量范围").grid(row=1, column=0, columnspan=4, padx=5, pady=1, sticky=tk.W)
        
#         # 文件编码选项
#         encoding_frame = ttk.LabelFrame(control_frame, text="文件编码选项", padding="5")
#         encoding_frame.pack(fill=tk.X, pady=5)
        
#         ttk.Label(encoding_frame, text="文件编码:").grid(row=0, column=0, padx=5, pady=2)
#         self.encoding_var = tk.StringVar(value="自动检测")
#         encoding_combo = ttk.Combobox(encoding_frame, textvariable=self.encoding_var, 
#                                       values=["自动检测", "utf-8", "gbk", "gb2312", "utf-16"],
#                                       width=15)
#         encoding_combo.grid(row=0, column=1, padx=5, pady=2)
        
#         # 日期格式选项
#         date_format_frame = ttk.LabelFrame(control_frame, text="数据日期格式", padding="5")
#         date_format_frame.pack(fill=tk.X, pady=5)
        
#         ttk.Label(date_format_frame, text="数据日期格式:").grid(row=0, column=0, padx=5, pady=2)
#         self.date_format_var = tk.StringVar(value="YYYY-MM-DD")
#         date_format_combo = ttk.Combobox(date_format_frame, textvariable=self.date_format_var, 
#                                         values=["YYYY-MM-DD", "YYYY/MM/DD", "YYYYMMDD", "YYYY.MM.DD"],
#                                         width=15)
#         date_format_combo.grid(row=0, column=1, padx=5, pady=2)
        
#         # 分析选项
#         ttk.Label(control_frame, text="分析选项:").pack(anchor=tk.W, pady=10)
        
#         self.contract_vars = {}
#         for contract in self.contract_types:
#             var = tk.BooleanVar(value=True)
#             ttk.Checkbutton(control_frame, text=f"{contract} ({self.index_mapping[contract]})", variable=var).pack(anchor=tk.W, pady=2)
#             self.contract_vars[contract] = var
        
#         # 滞后分析选项
#         lag_frame = ttk.LabelFrame(control_frame, text="滞后分析选项", padding="5")
#         lag_frame.pack(fill=tk.X, pady=5)
        
#         ttk.Label(lag_frame, text="净空单数据滞后天数:").grid(row=0, column=0, padx=5, pady=2)
#         self.lag_days_var = tk.StringVar(value="0")
#         lag_days_combo = ttk.Combobox(lag_frame, textvariable=self.lag_days_var, 
#                                       values=["0", "1", "2", "3"],
#                                       width=5)
#         lag_days_combo.grid(row=0, column=1, padx=5, pady=2)
#         ttk.Label(lag_frame, text="0=不滞后，1=滞后1天，以此类推").grid(row=0, column=2, padx=5, pady=2)
        
#         # 获取并保存指数数据按钮
#         ttk.Button(control_frame, text="获取并保存指数数据", command=self.fetch_and_save_index_data).pack(pady=5)
        
#         # 执行按钮
#         ttk.Button(control_frame, text="执行分析", command=self.run_analysis_thread).pack(pady=20)
        
#         # 日志区域
#         ttk.Label(control_frame, text="操作日志:").pack(anchor=tk.W, pady=10)
#         self.log_text = scrolledtext.ScrolledText(control_frame, width=40, height=15)
#         self.log_text.pack(fill=tk.BOTH, expand=True)
        
#         # 右侧结果展示面板
#         results_frame = ttk.LabelFrame(main_frame, text="分析结果", padding="10")
#         results_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5)
        
#         # 创建选项卡控件
#         self.tab_control = ttk.Notebook(results_frame)
#         self.tab_control.pack(fill=tk.BOTH, expand=True)
        
#         # 为每个合约类型创建选项卡
#         self.contract_tabs = {}
#         for contract in self.contract_types:
#             tab = ttk.Frame(self.tab_control)
#             self.tab_control.add(tab, text=f"{contract}分析")
#             self.contract_tabs[contract] = tab
        
#         # 汇总结果选项卡
#         self.summary_tab = ttk.Frame(self.tab_control)
#         self.tab_control.add(self.summary_tab, text="汇总结果")
        
#         # 滞后分析结果选项卡
#         self.lag_analysis_tab = ttk.Frame(self.tab_control)
#         self.tab_control.add(self.lag_analysis_tab, text="滞后分析对比")
    
#     def browse_futures_file(self):
#         """浏览并选择期货数据文件"""
#         file_path = filedialog.askopenfilename(
#             title="选择期货净空单数据文件",
#             filetypes=[("CSV文件", "*.csv"), ("所有文件", "*.*")]
#         )
#         if file_path:
#             self.futures_file_var.set(file_path)
#             self.log(f"已选择文件: {file_path}")
    
#     def log(self, message):
#         """添加日志信息"""
#         self.log_text.insert(tk.END, f"{message}\n")
#         self.log_text.see(tk.END)
#         self.root.update_idletasks()
    
#     def run_analysis_thread(self):
#         """在单独线程中运行分析，避免界面卡顿"""
#         if not self.futures_file_var.get():
#             messagebox.showerror("错误", "请先选择期货净空单数据文件")
#             return
        
#         # 禁用按钮防止重复点击
#         threading.Thread(target=self.run_analysis, daemon=True).start()
    
#     def run_analysis(self):
#         """执行数据分析"""
#         try:
#             # 重置结果
#             self.analysis_results = {}
            
#             # 加载期货数据
#             self.log("正在加载期货数据...")
#             self.futures_data = self.load_data(self.futures_file_var.get())
            
#             if self.futures_data is None:
#                 self.log("无法加载期货数据，请检查文件格式")
#                 return
            
#             # 获取用户指定的日期范围
#             user_start_date = self.start_date_var.get().strip()
#             user_end_date = self.end_date_var.get().strip()
            
#             # 转换用户输入的日期格式为标准格式 (YYYY-MM-DD)
#             start_date = self._parse_date(user_start_date)
#             end_date = self._parse_date(user_end_date)
            
#             # 确定期货数据的日期范围
#             try:
#                 # 使用指定的日期格式解析数据中的日期
#                 date_format = self.get_date_format()
#                 self.futures_data['日期'] = pd.to_datetime(self.futures_data['日期'], format=date_format)
#                 data_min_date = self.futures_data['日期'].min().strftime('%Y-%m-%d')
#                 data_max_date = self.futures_data['日期'].max().strftime('%Y-%m-%d')
                
#                 # 确定最终使用的分析日期范围
#                 final_start = start_date if start_date else data_min_date
#                 final_end = end_date if end_date else data_max_date
                
#                 # 转换为datetime对象以便比较
#                 final_start_dt = pd.to_datetime(final_start)
#                 final_end_dt = pd.to_datetime(final_end)
                
#                 # 确保开始日期不晚于结束日期
#                 if final_start_dt > final_end_dt:
#                     self.log(f"警告: 开始日期 {final_start} 晚于结束日期 {final_end}，已交换顺序")
#                     final_start, final_end = final_end, final_start
#                     final_start_dt, final_end_dt = final_end_dt, final_start_dt
                
#                 # 确保日期范围在数据范围内
#                 data_min_dt = pd.to_datetime(data_min_date)
#                 data_max_dt = pd.to_datetime(data_max_date)
                
#                 if final_start_dt < data_min_dt:
#                     self.log(f"警告: 开始日期 {final_start} 早于数据最早日期 {data_min_date}，已调整为 {data_min_date}")
#                     final_start = data_min_date
#                     final_start_dt = data_min_dt
                
#                 if final_end_dt > data_max_dt:
#                     self.log(f"警告: 结束日期 {final_end} 晚于数据最晚日期 {data_max_date}，已调整为 {data_max_date}")
#                     final_end = data_max_date
#                     final_end_dt = data_max_dt
                
#                 self.log(f"期货数据日期范围: {data_min_date} 至 {data_max_date}")
#                 self.log(f"使用分析日期范围: {final_start} 至 {final_end}")
                
#                 # 筛选期货数据
#                 self.futures_data = self.futures_data[
#                     (self.futures_data['日期'] >= final_start_dt) & 
#                     (self.futures_data['日期'] <= final_end_dt)
#                 ]
                
#                 self.log(f"筛选后期货数据: {len(self.futures_data)} 行")
                
#             except Exception as e:
#                 self.log(f"日期解析或筛选错误: {str(e)}")
#                 self.log("使用未筛选的期货数据")
        
#         except Exception as e:
#             self.log(f"分析准备阶段出错: {str(e)}")
#             messagebox.showerror("错误", f"分析准备阶段出错: {str(e)}")
#             return
        
#         try:
#             # 获取用户指定的滞后天数
#             try:
#                 lag_days = int(self.lag_days_var.get())
#                 if lag_days < 0 or lag_days > 3:
#                     lag_days = 0
#                     self.log("警告: 滞后天数应在0-3之间，已设为0")
#                 self.log(f"使用净空单数据滞后天数: {lag_days}")
#             except ValueError:
#                 lag_days = 0
#                 self.log("警告: 滞后天数无效，已设为0")
            
#             # 分析选中的合约
#             selected_contracts = [contract for contract, var in self.contract_vars.items() if var.get()]
#             if not selected_contracts:
#                 self.log("请至少选择一个合约类型")
#                 return
            
#             # 执行常规分析
#             for contract in selected_contracts:
#                 self.log(f"\n正在分析 {contract} 期货数据（滞后{lag_days}天）...")
#                 self.analyze_contract(contract, lag_days)
            
#             # 如果选择了滞后分析，执行多日滞后对比分析
#             if lag_days > 0:
#                 self.perform_lag_analysis_comparison(selected_contracts)
            
#             # 显示汇总结果
#             self.display_summary_results()
            
#             self.log("\n分析完成！")
            
#         except Exception as e:
#             self.log(f"分析过程中出错: {str(e)}")
#             messagebox.showerror("错误", f"分析过程中出错: {str(e)}")
    
#     def _parse_date(self, date_str):
#         """解析用户输入的日期，返回标准格式 (YYYY-MM-DD) 或None"""
#         if not date_str:
#             return None
        
#         try:
#             # 尝试按用户输入的格式解析
#             date_format = self.date_format_var.get()
#             format_map = {
#                 "YYYY-MM-DD": "%Y-%m-%d",
#                 "YYYY/MM/DD": "%Y/%m/%d",
#                 "YYYYMMDD": "%Y%m%d",
#                 "YYYY.MM.DD": "%Y.%m.%d"
#             }
#             date_obj = pd.to_datetime(date_str, format=format_map.get(date_format, "%Y-%m-%d"))
#             return date_obj.strftime('%Y-%m-%d')
#         except Exception as e:
#             self.log(f"日期解析错误: {date_str} - {str(e)}")
#             messagebox.showerror("日期格式错误", f"无法解析日期 '{date_str}'\n请使用格式: {self.date_format_var.get()}")
#             return None
    
#     def get_date_format(self):
#         """获取数据日期格式字符串"""
#         format_map = {
#             "YYYY-MM-DD": "%Y-%m-%d",
#             "YYYY/MM/DD": "%Y/%m/%d",
#             "YYYYMMDD": "%Y%m%d",
#             "YYYY.MM.DD": "%Y.%m.%d"
#         }
#         return format_map.get(self.date_format_var.get(), "%Y-%m-%d")
    
#     def detect_file_encoding(self, file_path):
#         """检测文件编码"""
#         try:
#             with open(file_path, 'rb') as f:
#                 raw_data = f.read(10240)  # 读取前10KB数据进行编码检测
            
#             result = chardet.detect(raw_data)
#             encoding = result['encoding']
#             confidence = result['confidence']
            
#             self.log(f"检测到文件编码: {encoding}，置信度: {confidence:.2f}")
#             return encoding
#         except Exception as e:
#             self.log(f"编码检测失败: {str(e)}")
#             return 'utf-8'  # 默认使用utf-8
    
#     def load_data(self, file_path):
#         """加载数据文件"""
#         try:
#             if not os.path.exists(file_path):
#                 self.log(f"文件不存在: {file_path}")
#                 return None
            
#             # 获取用户选择的编码或自动检测
#             encoding = self.encoding_var.get()
#             if encoding == "自动检测":
#                 encoding = self.detect_file_encoding(file_path)
            
#             # 尝试自动检测分隔符
#             with open(file_path, 'r', encoding=encoding) as f:
#                 first_line = f.readline().strip()
#                 if '\t' in first_line:
#                     sep = '\t'
#                     self.log("检测到文件使用制表符分隔")
#                 elif ';' in first_line:
#                     sep = ';'
#                     self.log("检测到文件使用分号分隔")
#                 else:
#                     sep = ','
#                     self.log("检测到文件使用逗号分隔")
            
#             # 读取CSV文件
#             data = pd.read_csv(file_path, sep=sep, encoding=encoding)
#             self.log(f"成功加载数据: {file_path}")
#             self.log(f"数据包含 {len(data)} 行，{len(data.columns)} 列")
#             self.log(f"列名: {', '.join(data.columns.tolist())}")
            
#             return data
#         except UnicodeDecodeError as e:
#             self.log(f"编码错误: 无法使用 {encoding} 编码读取文件")
#             self.log(f"错误详情: {str(e)}")
#             self.log("请尝试手动选择其他编码")
#             return None
#         except Exception as e:
#             self.log(f"加载数据时出错: {str(e)}")
#             return None
    
#     def get_index_data_from_api(self, contract_type, start_date=None, end_date=None):
#         """通过akshare API获取指数数据"""
#         self.log(f"从API获取{contract_type}({self.index_mapping[contract_type]})指数数据...")
        
#         # 映射期货品种到对应的指数代码
#         index_code_mapping = {
#             'IF': '000300',  # 沪深300指数
#             'IC': '000905',  # 中证500指数
#             'IM': '000852',  # 中证1000指数
#             'IH': '000016'   # 上证50指数
#         }
        
#         if contract_type not in index_code_mapping:
#             self.log(f"不支持的期货品种: {contract_type}")
#             return None
        
#         index_code = index_code_mapping[contract_type]
        
#         try:
#             self.log("正在请求API数据...")
            
#             # 尝试获取指数数据
#             try:
#                 # 先尝试新版API
#                 index_data = ak.stock_zh_index_daily(symbol=f"sh{index_code}")
#                 self.log(f"成功获取{contract_type}指数数据（新版API）")
#             except Exception as e:
#                 # 尝试旧版API
#                 self.log(f"新版API失败，尝试旧版API: {str(e)}")
#                 index_data = ak.stock_zh_index_daily_em(symbol=index_code)
#                 self.log(f"成功获取{contract_type}指数数据（旧版API）")
            
#             self.log(f"API返回数据: {len(index_data)} 行，{len(index_data.columns)} 列")
#             self.log(f"API返回列名: {', '.join(index_data.columns.tolist())}")
            
#             # 数据处理逻辑
#             if len(index_data.columns) >= 5:
#                 # 假设前5列是日期、开盘价、最高价、最低价、收盘价
#                 index_data = index_data.iloc[:, :5].copy()
#                 index_data.columns = ['日期', '开盘价', '最高价', '最低价', '收盘价']
#             else:
#                 raise ValueError(f"API返回列数不足: {len(index_data.columns)} 列")
            
#             # 确保日期列是日期类型
#             index_data['日期'] = pd.to_datetime(index_data['日期'])
            
#             # 筛选日期范围
#             if start_date:
#                 index_data = index_data[index_data['日期'] >= start_date]
#             if end_date:
#                 index_data = index_data[index_data['日期'] <= end_date]
            
#             # 为滞后分析扩展日期范围
#             if start_date:
#                 extend_days = pd.Timedelta(days=4)  # 覆盖0-3天的滞后
#                 extended_start = pd.to_datetime(start_date) - extend_days
#                 try:
#                     extended_data = ak.stock_zh_index_daily(symbol=f"sh{index_code}")
#                     extended_data['日期'] = pd.to_datetime(extended_data['日期'])
#                     extended_data = extended_data[
#                         (extended_data['日期'] >= extended_start) & 
#                         (extended_data['日期'] <= end_date)
#                     ]
#                     if not extended_data.empty:
#                         index_data = extended_data
#                         self.log(f"为滞后分析扩展日期范围至: {extended_start.strftime('%Y-%m-%d')}")
#                 except Exception as e:
#                     self.log(f"扩展日期范围失败: {str(e)}")
            
#             self.log(f"筛选后指数数据: {len(index_data)} 行")
            
#             return index_data
#         except Exception as e:
#             self.log(f"获取{contract_type}指数数据时出错: {str(e)}")
#             import traceback
#             self.log(f"详细错误堆栈:\n{traceback.format_exc()}")
#             return None
    
#     def save_index_data(self, index_data, contract_type):
#         """保存指数数据到文件"""
#         if index_data is None or index_data.empty:
#             self.log(f"无法保存{contract_type}指数数据：数据为空")
#             return False
        
#         try:
#             # 确保保存目录存在
#             save_dir = os.path.dirname(self.futures_file_var.get())
#             if not os.path.exists(save_dir):
#                 os.makedirs(save_dir)
            
#             # 保存到文件
#             file_name = os.path.join(save_dir, f"{contract_type}_指数数据.csv")
#             index_data.to_csv(file_name, index=False)
#             self.log(f"已成功将{contract_type}指数数据保存至: {file_name}")
#             return True
#         except Exception as e:
#             self.log(f"保存{contract_type}指数数据时出错: {str(e)}")
#             return False
    
#     def fetch_and_save_index_data(self):
#         """获取并保存指数数据"""
#         if not self.futures_file_var.get():
#             messagebox.showerror("错误", "请先选择期货净空单数据文件")
#             return
        
#         # 获取用户指定的日期范围
#         user_start_date = self.start_date_var.get().strip()
#         user_end_date = self.end_date_var.get().strip()
        
#         # 解析日期
#         start_date = self._parse_date(user_start_date)
#         end_date = self._parse_date(user_end_date)
        
#         # 获取选中的合约
#         selected_contracts = [contract for contract, var in self.contract_vars.items() if var.get()]
#         if not selected_contracts:
#             self.log("请至少选择一个合约类型")
#             return
        
#         self.log("开始获取并保存指数数据...")
        
#         # 在单独线程中执行，避免界面卡顿
#         threading.Thread(target=self._fetch_and_save_index_data_thread, 
#                          args=(selected_contracts, start_date, end_date), 
#                          daemon=True).start()
    
#     def _fetch_and_save_index_data_thread(self, contracts, start_date, end_date):
#         """在线程中执行获取并保存指数数据的操作"""
#         success_count = 0
#         for contract in contracts:
#             self.log(f"\n正在获取{contract}({self.index_mapping[contract]})指数数据...")
#             index_data = self.get_index_data_from_api(contract, start_date, end_date)
            
#             if index_data is not None and not index_data.empty:
#                 if self.save_index_data(index_data, contract):
#                     success_count += 1
#                 else:
#                     self.log(f"保存{contract}指数数据失败")
#             else:
#                 self.log(f"获取{contract}指数数据失败或数据为空")
        
#         self.log(f"\n指数数据获取完成: {success_count} 个成功, {len(contracts) - success_count} 个失败")
#         messagebox.showinfo("完成", f"指数数据获取完成: {success_count} 个成功, {len(contracts) - success_count} 个失败")
    
#     def calculate_net_short_increase(self, data, contract_type):
#         """计算特定期货合约的净空单增量"""
#         # 提取特定期货的净空单数据
#         contract_data = data[['日期', contract_type]].copy()
#         contract_data.columns = ['日期', '净空单']
        
#         # 计算净空单增量
#         contract_data['净空单增量'] = contract_data['净空单'].diff()
        
#         return contract_data
    
#     def filter_index_data_by_futures_dates(self, futures_data, index_data):
#         """根据期货数据的日期筛选指数数据"""
#         # 获取期货数据中的所有日期
#         futures_dates = set(futures_data['日期'].dt.strftime('%Y-%m-%d'))
        
#         # 筛选指数数据，只保留期货数据中存在的日期
#         filtered_index_data = index_data[
#             index_data['日期'].dt.strftime('%Y-%m-%d').isin(futures_dates)
#         ].copy()
        
#         # 计算匹配率
#         matched_ratio = len(filtered_index_data) / len(index_data) if len(index_data) > 0 else 0
        
#         self.log(f"指数数据共 {len(index_data)} 行，匹配期货数据日期的有 {len(filtered_index_data)} 行")
#         self.log(f"日期匹配率: {matched_ratio:.2%}")
        
#         if len(filtered_index_data) < len(index_data):
#             self.log("警告: 部分指数数据日期在期货数据中不存在，已被过滤")
        
#         return filtered_index_data
    
#     def lag_futures_data(self, futures_data, lag_days):
#         """对期货数据进行滞后处理"""
#         if lag_days <= 0:
#             return futures_data.copy()
        
#         self.log(f"对期货数据进行{lag_days}天滞后处理...")
        
#         # 创建滞后的期货数据副本
#         lagged_data = futures_data.copy()
        
#         # 将净空单增量数据向后移动lag_days天
#         lagged_data['净空单增量'] = lagged_data['净空单增量'].shift(lag_days)
        
#         # 移除因滞后产生的NaN值
#         original_count = len(lagged_data)
#         lagged_data = lagged_data.dropna(subset=['净空单增量'])
#         removed_count = original_count - len(lagged_data)
        
#         self.log(f"因滞后处理移除了 {removed_count} 行数据")
        
#         return lagged_data
    
#     def analyze_contract(self, contract_type, lag_days=0):
#         """分析单个合约"""
#         try:
#             # 计算净空单增量
#             contract_results = self.calculate_net_short_increase(self.futures_data, contract_type)
            
#             # 尝试加载指数数据
#             index_file = os.path.join(os.path.dirname(self.futures_file_var.get()), 
#                                      f"{contract_type}_指数数据.csv")
#             index_data = self.load_data(index_file)
            
#             # 如果指数数据不存在，从API获取
#             if index_data is None:
#                 self.log(f"未找到{contract_type}指数数据文件，将从API获取...")
#                 # 使用当前分析的日期范围获取指数数据
#                 start_date = self.start_date_var.get().strip()
#                 end_date = self.end_date_var.get().strip()
#                 index_data = self.get_index_data_from_api(contract_type, start_date, end_date)
#                 if index_data is None:
#                     self.log(f"跳过{contract_type}分析：无法获取指数数据")
#                     return
                
#                 # 保存获取的指数数据
#                 if not self.save_index_data(index_data, contract_type):
#                     self.log(f"警告: 无法保存{contract_type}指数数据，将继续分析")
            
#             # 确保指数数据的日期格式一致
#             index_data['日期'] = pd.to_datetime(index_data['日期'])
            
#             # 以期货数据的日期为准，筛选指数数据
#             self.log(f"\n开始根据{contract_type}期货数据的日期筛选指数数据...")
#             filtered_index_data = self.filter_index_data_by_futures_dates(contract_results, index_data)
            
#             if len(filtered_index_data) == 0:
#                 self.log(f"错误: 筛选后{contract_type}指数数据为空，无法进行分析")
#                 return
            
#             # 对期货数据进行滞后处理
#             if lag_days > 0:
#                 contract_results = self.lag_futures_data(contract_results, lag_days)
            
#             # 确保滞后处理后还有足够的数据
#             if len(contract_results) < 10:
#                 self.log(f"错误: 滞后处理后{contract_type}期货数据不足，无法进行分析")
#                 return
            
#             # 重新筛选指数数据，确保与滞后的期货数据匹配
#             filtered_index_data = self.filter_index_data_by_futures_dates(contract_results, filtered_index_data)
            
#             if len(filtered_index_data) < 10:
#                 self.log(f"错误: 滞后处理后{contract_type}匹配的指数数据不足，无法进行分析")
#                 return
            
#             # 分析相关性
#             correlation = self.analyze_correlation(contract_results, filtered_index_data, contract_type, lag_days)
#             self.analysis_results[(contract_type, lag_days)] = correlation
            
#             # 合并数据用于可视化
#             viz_data = pd.merge(contract_results, filtered_index_data, on='日期', how='inner')
#             viz_data['指数涨跌幅'] = viz_data['收盘价'].pct_change() * 100
            
#             # 检查合并后的数据量
#             if len(viz_data) < 10:
#                 self.log(f"警告: {contract_type}的合并数据量较少 ({len(viz_data)} 行)，结果可能不可靠")
            
#             # 可视化结果
#             self.display_contract_results(contract_type, viz_data, correlation, lag_days)
            
#             self.log(f"{contract_type}期货分析完成（滞后{lag_days}天）: {correlation['结论']}")
            
#         except Exception as e:
#             self.log(f"分析{contract_type}期货时出错: {str(e)}")
    
#     def analyze_correlation(self, futures_data, index_data, contract_type, lag_days=0):
#         """分析期货净空单增量与指数涨跌的关系"""
#         # 合并期货和指数数据
#         merged_data = pd.merge(futures_data, index_data, on='日期', how='inner')
        
#         # 计算指数涨跌幅
#         merged_data['指数涨跌幅'] = merged_data['收盘价'].pct_change() * 100
        
#         # 计算相关系数和p值
#         valid_data = merged_data.dropna(subset=['净空单增量', '指数涨跌幅'])
#         if len(valid_data) < 2:
#             return {
#                 '合约类型': contract_type,
#                 '滞后天数': lag_days,
#                 '相关系数': np.nan,
#                 'p值': np.nan,
#                 '数据点数': 0,
#                 '结论': '数据不足，无法计算相关性'
#             }
        
#         corr, p_value = pearsonr(valid_data['净空单增量'], valid_data['指数涨跌幅'])
        
#         # 确定相关性方向和强度
#         if np.abs(corr) < 0.1:
#             strength = "极弱"
#         elif np.abs(corr) < 0.3:
#             strength = "弱"
#         elif np.abs(corr) < 0.5:
#             strength = "中等"
#         else:
#             strength = "强"
        
#         direction = "正" if corr > 0 else "负"
        
#         return {
#             '合约类型': contract_type,
#             '滞后天数': lag_days,
#             '相关系数': corr,
#             'p值': p_value,
#             '数据点数': len(valid_data),
#             '相关性强度': strength,
#             '相关性方向': direction,
#             '结论': f"{direction}{strength}相关" if p_value < 0.05 else "不显著相关"
#         }
    
#     def perform_lag_analysis_comparison(self, contracts):
#         """执行多日滞后分析对比"""
#         self.log("\n开始执行滞后分析对比...")
        
#         # 为每个合约执行0-3天的滞后分析
#         all_lag_results = {}
        
#         # 获取用户指定的日期范围
#         start_date = self.start_date_var.get().strip()
#         end_date = self.end_date_var.get().strip()
        
#         for contract in contracts:
#             contract_lag_results = []
            
#             for lag in range(4):  # 0,1,2,3天滞后
#                 self.log(f"\n分析 {contract} 期货数据（滞后{lag}天）...")
                
#                 # 计算净空单增量
#                 contract_results = self.calculate_net_short_increase(self.futures_data, contract)
                
#                 # 加载指数数据
#                 index_file = os.path.join(os.path.dirname(self.futures_file_var.get()), 
#                                          f"{contract}_指数数据.csv")
#                 index_data = self.load_data(index_file)
                
#                 if index_data is None:
#                     self.log(f"未找到{contract}指数数据文件，跳过滞后{lag}天分析")
#                     continue
                
#                 # 确保指数数据的日期格式一致
#                 index_data['日期'] = pd.to_datetime(index_data['日期'])
                
#                 # 筛选指数数据
#                 filtered_index_data = self.filter_index_data_by_futures_dates(contract_results, index_data)
                
#                 if len(filtered_index_data) == 0:
#                     self.log(f"错误: 筛选后{contract}指数数据为空，跳过滞后{lag}天分析")
#                     continue
                
#                 # 对期货数据进行滞后处理
#                 if lag > 0:
#                     contract_results = self.lag_futures_data(contract_results, lag)
                
#                 if len(contract_results) < 10:
#                     self.log(f"错误: 滞后{lag}天后{contract}期货数据不足，跳过分析")
#                     continue
                
#                 # 重新筛选指数数据
#                 filtered_index_data = self.filter_index_data_by_futures_dates(contract_results, filtered_index_data)
                
#                 if len(filtered_index_data) < 10:
#                     self.log(f"错误: 滞后{lag}天后{contract}匹配的指数数据不足，跳过分析")
#                     continue
                
#                 # 分析相关性
#                 correlation = self.analyze_correlation(contract_results, filtered_index_data, contract, lag)
#                 contract_lag_results.append(correlation)
            
#             if contract_lag_results:
#                 all_lag_results[contract] = contract_lag_results
        
#         # 显示滞后分析结果
#         self.display_lag_analysis_results(all_lag_results)
    
#     # def display_contract_results(self, contract_type, data, correlation, lag_days=0):
#     #     """在选项卡中显示合约分析结果"""
#     #     # 清空当前选项卡
#     #     for widget in self.contract_tabs[contract_type].winfo_children():
#     #         widget.destroy()
        
#     #     # 创建结果显示框架
#     #     results_frame = ttk.Frame(self.contract_tabs[contract_type], padding="10")
#     #     results_frame.pack(fill=tk.BOTH, expand=True)
        
#     #     # 显示基本信息
#     #     info_frame = ttk.LabelFrame(results_frame, text=f"{contract_type}期货分析结果（滞后{lag_days}天）", padding="10")
#     #     info_frame.pack(fill=tk.X, pady=5)
        
#     #     ttk.Label(info_frame, text=f"分析结论: {correlation['结论']}").grid(row=0, column=0, sticky=tk.W, padx=5, pady=2)
#     #     ttk.Label(info_frame, text=f"相关系数: {correlation['相关系数']:.4f}").grid(row=1, column=0, sticky=tk.W, padx=5, pady=2)
#     #     ttk.Label(info_frame, text=f"p值: {correlation['p值']:.4f}").grid(row=2, column=0, sticky=tk.W, padx=5, pady=2)
#     #     ttk.Label(info_frame, text=f"数据点数: {correlation['数据点数']}").grid(row=0, column=1, sticky=tk.W, padx=5, pady=2)
        
#     #     # 创建可交互的双Y轴图表
#     #     fig = Figure(figsize=(12, 8), dpi=100)
#     #     ax1 = fig.add_subplot(111)
        
#     #     # 绘制净空单增量（左Y轴）
#     #     ax1.bar(data['日期'], data['净空单增量'], label='净空单增量', color='green', alpha=0.7)
#     #     ax1.set_ylabel('净空单增量', color='green')
#     #     ax1.tick_params(axis='y', labelcolor='green')
        
#     #     # 创建第二个Y轴用于指数涨跌幅
#     #     ax2 = ax1.twinx()
#     #     ax2.plot(data['日期'], data['指数涨跌幅'], label='指数涨跌幅(%)', color='red', linewidth=2)
#     #     ax2.set_ylabel('指数涨跌幅(%)', color='red')
#     #     ax2.tick_params(axis='y', labelcolor='red')
        
#     #     # 设置图表标题和X轴标签
#     #     ax1.set_title(f'{contract_type}期货净空单增量与指数涨跌幅对比（滞后{lag_days}天）')
#     #     ax1.set_xlabel('日期')
        
#     #     # 添加图例
#     #     lines1, labels1 = ax1.get_legend_handles_labels()
#     #     lines2, labels2 = ax2.get_legend_handles_labels()
#     #     ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper right')
        
#     #     # 启用网格
#     #     ax1.grid(True, linestyle='--', alpha=0.7)
        
#     #     # 调整布局
#     #     fig.tight_layout()
        
#     #     # 创建画布和工具栏
#     #     canvas = FigureCanvasTkAgg(fig, master=results_frame)
#     #     canvas.draw()
#     #     canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
        
#     #     # 使用自定义工具栏，确保必要的工具项显示
#     #     class CustomToolbar(NavigationToolbar2Tk):
#     #         toolitems = [t for t in NavigationToolbar2Tk.toolitems if
#     #                      t[0] in ('Home', 'Back', 'Forward', 'Pan', 'Zoom', 'Save')]
        
#     #     toolbar = CustomToolbar(canvas, results_frame)
#     #     toolbar.update()
        
#     #     # 添加鼠标滚轮缩放功能（兼容不同版本）
#     #     def on_mouse_wheel(event):
#     #         if event.inaxes:
#     #             ax = event.inaxes
#     #             xlim = ax.get_xlim()
#     #             ylim = ax.get_ylim()
                
#     #             xdata = event.xdata  # 鼠标在数据坐标系中的x坐标
#     #             ydata = event.ydata  # 鼠标在数据坐标系中的y坐标
                
#     #             # 尝试获取滚动量，兼容不同版本的matplotlib
#     #             try:
#     #                 scroll = event.delta
#     #             except AttributeError:
#     #                 scroll = -event.step
                
#     #             # 计算缩放比例
#     #             scale_factor = 0.9 if scroll > 0 else 1.1
                
#     #             # 计算新的坐标范围
#     #             new_xlim = (
#     #                 xdata - (xdata - xlim[0]) * scale_factor,
#     #                 xdata + (xlim[1] - xdata) * scale_factor
#     #             )
#     #             new_ylim = (
#     #                 ydata - (ydata - ylim[0]) * scale_factor,
#     #                 ydata + (ylim[1] - ydata) * scale_factor
#     #             )
                
#     #             # 设置新的坐标范围
#     #             ax.set_xlim(new_xlim)
#     #             ax.set_ylim(new_ylim)
#     #             canvas.draw()
        
#     #     # 连接鼠标滚轮事件
#     #     canvas.mpl_connect('scroll_event', on_mouse_wheel)
        
#     #     # 添加快捷键提示
#     #     ttk.Label(results_frame, text="图表操作提示:").pack(pady=5, anchor=tk.W)
#     #     ttk.Label(results_frame, text="  - 工具栏: 点击图表下方的按钮进行操作").pack(anchor=tk.W)
#     #     ttk.Label(results_frame, text="  - 鼠标滚轮: 放大/缩小").pack(anchor=tk.W)
#     #     ttk.Label(results_frame, text="  - 键盘快捷键:").pack(anchor=tk.W)
#     #     ttk.Label(results_frame, text="    • '+' 键: 放大").pack(anchor=tk.W)
#     #     ttk.Label(results_frame, text="    • '-' 键: 缩小").pack(anchor=tk.W)
#     #     ttk.Label(results_frame, text="    • 'p' 键: 平移模式").pack(anchor=tk.W)
#     #     ttk.Label(results_frame, text="    • 'o' 键: 矩形缩放模式").pack(anchor=tk.W)
#     #     ttk.Label(results_frame, text="    • 'h' 或 'r' 键: 重置视图").pack(anchor=tk.W)

#     def display_contract_results(self, contract_type, data, correlation, lag_days=0):
#         """在选项卡中显示合约分析结果"""
#         # 清空当前选项卡
#         for widget in self.contract_tabs[contract_type].winfo_children():
#             widget.destroy()
        
#         # 创建结果显示框架
#         results_frame = ttk.Frame(self.contract_tabs[contract_type], padding="10")
#         results_frame.pack(fill=tk.BOTH, expand=True)
        
#         # 显示基本信息
#         info_frame = ttk.LabelFrame(results_frame, text=f"{contract_type}期货分析结果（滞后{lag_days}天）", padding="10")
#         info_frame.pack(fill=tk.X, pady=5)
        
#         ttk.Label(info_frame, text=f"分析结论: {correlation['结论']}").grid(row=0, column=0, sticky=tk.W, padx=5, pady=2)
#         ttk.Label(info_frame, text=f"相关系数: {correlation['相关系数']:.4f}").grid(row=1, column=0, sticky=tk.W, padx=5, pady=2)
#         ttk.Label(info_frame, text=f"p值: {correlation['p值']:.4f}").grid(row=2, column=0, sticky=tk.W, padx=5, pady=2)
#         ttk.Label(info_frame, text=f"数据点数: {correlation['数据点数']}").grid(row=0, column=1, sticky=tk.W, padx=5, pady=2)
        
#         # 创建可交互的双Y轴图表
#         fig = Figure(figsize=(12, 8), dpi=100)
#         ax1 = fig.add_subplot(111)
        
#         # 绘制净空单增量（左Y轴，折线图）
#         ax1.plot(data['日期'], data['净空单增量'], label='净空单增量', color='blue', linewidth=1.5)
#         ax1.set_ylabel('净空单增量', color='blue')
#         ax1.tick_params(axis='y', labelcolor='blue')
        
#         # 添加0轴参考线
#         ax1.axhline(y=0, color='black', linestyle='-', alpha=0.3, linewidth=1)
        
#         # 创建第二个Y轴用于指数涨跌幅
#         ax2 = ax1.twinx()
#         ax2.plot(data['日期'], data['指数涨跌幅'], label='指数涨跌幅(%)', color='red', linewidth=1.5)
#         ax2.set_ylabel('指数涨跌幅(%)', color='red')
#         ax2.tick_params(axis='y', labelcolor='red')
        
#         # 添加0轴参考线
#         ax2.axhline(y=0, color='black', linestyle='-', alpha=0.3, linewidth=1)
        
#         # 设置图表标题和X轴标签
#         ax1.set_title(f'{contract_type}期货净空单增量与指数涨跌幅对比（滞后{lag_days}天）')
#         ax1.set_xlabel('日期')
        
#         # 添加图例
#         lines1, labels1 = ax1.get_legend_handles_labels()
#         lines2, labels2 = ax2.get_legend_handles_labels()
#         ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper right')
        
#         # 启用网格
#         ax1.grid(True, linestyle='--', alpha=0.7)
        
#         # 调整布局
#         fig.tight_layout()
        
#         # 创建画布和工具栏
#         canvas = FigureCanvasTkAgg(fig, master=results_frame)
#         canvas.draw()
#         canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
        
#         # 使用自定义工具栏，确保必要的工具项显示
#         class CustomToolbar(NavigationToolbar2Tk):
#             toolitems = [t for t in NavigationToolbar2Tk.toolitems if
#                          t[0] in ('Home', 'Back', 'Forward', 'Pan', 'Zoom', 'Save')]
        
#         toolbar = CustomToolbar(canvas, results_frame)
#         toolbar.update()
        
#         # 添加鼠标滚轮缩放功能（兼容不同版本）
#         def on_mouse_wheel(event):
#             if event.inaxes:
#                 ax = event.inaxes
#                 xlim = ax.get_xlim()
#                 ylim = ax.get_ylim()
                
#                 xdata = event.xdata  # 鼠标在数据坐标系中的x坐标
#                 ydata = event.ydata  # 鼠标在数据坐标系中的y坐标
                
#                 # 尝试获取滚动量，兼容不同版本的matplotlib
#                 try:
#                     scroll = event.delta
#                 except AttributeError:
#                     scroll = -event.step
                
#                 # 计算缩放比例
#                 scale_factor = 0.9 if scroll > 0 else 1.1
                
#                 # 计算新的坐标范围
#                 new_xlim = (
#                     xdata - (xdata - xlim[0]) * scale_factor,
#                     xdata + (xlim[1] - xdata) * scale_factor
#                 )
#                 new_ylim = (
#                     ydata - (ydata - ylim[0]) * scale_factor,
#                     ydata + (ylim[1] - ydata) * scale_factor
#                 )
                
#                 # 设置新的坐标范围
#                 ax.set_xlim(new_xlim)
#                 ax.set_ylim(new_ylim)
#                 canvas.draw()
        
#         # 连接鼠标滚轮事件
#         canvas.mpl_connect('scroll_event', on_mouse_wheel)
        
#         # 添加快捷键提示
#         ttk.Label(results_frame, text="图表操作提示:").pack(pady=5, anchor=tk.W)
#         ttk.Label(results_frame, text="  - 工具栏: 点击图表下方的按钮进行操作").pack(anchor=tk.W)
#         ttk.Label(results_frame, text="  - 鼠标滚轮: 放大/缩小").pack(anchor=tk.W)
#         ttk.Label(results_frame, text="  - 键盘快捷键:").pack(anchor=tk.W)
#         ttk.Label(results_frame, text="    • '+' 键: 放大").pack(anchor=tk.W)
#         ttk.Label(results_frame, text="    • '-' 键: 缩小").pack(anchor=tk.W)
#         ttk.Label(results_frame, text="    • 'p' 键: 平移模式").pack(anchor=tk.W)
#         ttk.Label(results_frame, text="    • 'o' 键: 矩形缩放模式").pack(anchor=tk.W)
#         ttk.Label(results_frame, text="    • 'h' 或 'r' 键: 重置视图").pack(anchor=tk.W)
    
#     def display_summary_results(self):
#         """显示汇总结果"""
#         # 清空汇总选项卡
#         for widget in self.summary_tab.winfo_children():
#             widget.destroy()
        
#         # 创建结果表格
#         summary_frame = ttk.Frame(self.summary_tab, padding="10")
#         summary_frame.pack(fill=tk.BOTH, expand=True)
        
#         columns = ['合约类型', '滞后天数', '相关系数', 'p值', '数据点数', '相关性强度', '相关性方向', '结论']
#         tree = ttk.Treeview(summary_frame, columns=columns, show='headings')
        
#         # 设置列标题
#         for col in columns:
#             tree.heading(col, text=col)
#             width = 120 if col != '结论' else 200
#             tree.column(col, width=width, anchor=tk.CENTER)
        
#         # 添加数据
#         for key, result in self.analysis_results.items():
#             contract_type = key[0] if isinstance(key, tuple) else key
#             lag_days = key[1] if isinstance(key, tuple) else 0
            
#             tree.insert('', tk.END, values=[
#                 f"{contract_type} ({self.index_mapping[contract_type]})",
#                 lag_days,
#                 f"{result['相关系数']:.4f}",
#                 f"{result['p值']:.4f}",
#                 result['数据点数'],
#                 result['相关性强度'],
#                 result['相关性方向'],
#                 result['结论']
#             ])
        
#         tree.pack(fill=tk.BOTH, expand=True)
        
#         # 添加保存按钮
#         def save_results():
#             if not self.analysis_results:
#                 messagebox.showinfo("提示", "没有分析结果可保存")
#                 return
            
#             results_df = pd.DataFrame([result for result in self.analysis_results.values()])
#             save_path = filedialog.asksaveasfilename(
#                 title="保存分析结果",
#                 defaultextension=".csv",
#                 filetypes=[("CSV文件", "*.csv"), ("所有文件", "*.*")]
#             )
            
#             if save_path:
#                 results_df.to_csv(save_path, index=False)
#                 messagebox.showinfo("成功", f"分析结果已保存至: {save_path}")
        
#         ttk.Button(summary_frame, text="保存结果", command=save_results).pack(pady=10)
    
#     def display_lag_analysis_results(self, all_lag_results):
#         """显示滞后分析对比结果"""
#         # 清空滞后分析选项卡
#         for widget in self.lag_analysis_tab.winfo_children():
#             widget.destroy()
        
#         # 创建结果表格
#         lag_frame = ttk.Frame(self.lag_analysis_tab, padding="10")
#         lag_frame.pack(fill=tk.BOTH, expand=True)
        
#         columns = ['合约类型', '滞后0天相关系数', '滞后1天相关系数', '滞后2天相关系数', '滞后3天相关系数', 
#                   '最佳滞后天数', '最佳相关系数']
#         tree = ttk.Treeview(lag_frame, columns=columns, show='headings')
        
#         # 设置列标题
#         for col in columns:
#             tree.heading(col, text=col)
#             width = 120 if col != '合约类型' else 200
#             tree.column(col, width=width, anchor=tk.CENTER)
        
#         # 添加数据
#         for contract, results in all_lag_results.items():
#             # 确保有4个滞后结果
#             corr_values = [0, 0, 0, 0]
#             p_values = [1, 1, 1, 1]
            
#             for result in results:
#                 lag = result['滞后天数']
#                 if 0 <= lag <= 3:
#                     corr_values[lag] = result['相关系数']
#                     p_values[lag] = result['p值']
            
#             # 找出最佳相关系数（绝对值最大且p值显著）
#             best_lag = -1
#             best_corr = 0
            
#             for i in range(4):
#                 if p_values[i] < 0.05 and abs(corr_values[i]) > abs(best_corr):
#                     best_corr = corr_values[i]
#                     best_lag = i
            
#             tree.insert('', tk.END, values=[
#                 f"{contract} ({self.index_mapping[contract]})",
#                 f"{corr_values[0]:.4f}",
#                 f"{corr_values[1]:.4f}",
#                 f"{corr_values[2]:.4f}",
#                 f"{corr_values[3]:.4f}",
#                 best_lag if best_lag >= 0 else "无显著相关",
#                 f"{best_corr:.4f}" if best_lag >= 0 else "N/A"
#             ])
        
#         tree.pack(fill=tk.BOTH, expand=True)
        
#         # 创建滞后分析图表
#         if all_lag_results:
#             fig = Figure(figsize=(10, 6), dpi=100)
#             ax = fig.add_subplot(111)
            
#             # 为每个合约绘制相关系数随滞后天数变化的曲线
#             for contract, results in all_lag_results.items():
#                 lags = []
#                 corrs = []
                
#                 for result in results:
#                     if not np.isnan(result['相关系数']):
#                         lags.append(result['滞后天数'])
#                         corrs.append(result['相关系数'])
                
#                 if lags and corrs:
#                     ax.plot(lags, corrs, 'o-', label=f"{contract} ({self.index_mapping[contract]})")
            
#             ax.set_title('不同滞后天数的相关系数对比')
#             ax.set_xlabel('滞后天数')
#             ax.set_ylabel('相关系数')
#             ax.axhline(y=0, color='black', linestyle='-', linewidth=0.5)
#             ax.grid(True)
#             ax.legend()
            
#             fig.tight_layout()
            
#             # 将图表嵌入到Tkinter界面
#             canvas = FigureCanvasTkAgg(fig, master=self.lag_analysis_tab)
#             canvas.draw()
#             canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)

# if __name__ == "__main__":
#     # 确保chardet库已安装
#     try:
#         import chardet
#     except ImportError:
#         print("chardet库未安装，程序将尝试继续运行，但可能无法自动检测文件编码。")
#         print("请使用 'pip install chardet' 安装该库以获得完整功能。")
    
#     # 明确指定matplotlib后端
#     import matplotlib
#     matplotlib.use('TkAgg')
    
#     root = tk.Tk()
#     app = FuturesAnalysisApp(root)
#     root.mainloop() 


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import pearsonr
import akshare as ak
import os
import time
import tkinter as tk
from tkinter import ttk, filedialog, messagebox, scrolledtext
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.figure import Figure
import threading
import chardet  # 用于检测文件编码

# 设置matplotlib支持中文显示
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

class FuturesAnalysisApp:
    def __init__(self, root):
        self.root = root
        self.root.title("期货净空单与指数涨跌关系分析工具")
        self.root.geometry("1200x800")
        
        # 数据存储
        self.futures_data = None
        self.index_data = {}
        self.analysis_results = {}
        self.contract_types = ['IF', 'IC', 'IM', 'IH']
        self.index_mapping = {
            'IF': '沪深300指数',
            'IC': '中证500指数',
            'IM': '中证1000指数',
            'IH': '上证50指数'
        }
        
        # 创建界面
        self.create_widgets()
        
    def create_widgets(self):
        # 创建主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 左侧控制面板
        control_frame = ttk.LabelFrame(main_frame, text="控制面板", padding="10")
        control_frame.pack(side=tk.LEFT, fill=tk.Y, padx=5, pady=5)
        
        # 文件选择部分
        ttk.Label(control_frame, text="期货净空单数据文件:").pack(anchor=tk.W, pady=5)
        self.futures_file_var = tk.StringVar()
        futures_file_entry = ttk.Entry(control_frame, textvariable=self.futures_file_var, width=40)
        futures_file_entry.pack(anchor=tk.W, pady=2)
        
        ttk.Button(control_frame, text="浏览...", command=self.browse_futures_file).pack(anchor=tk.W, pady=2)
        
        # 日期范围选项
        date_frame = ttk.LabelFrame(control_frame, text="分析日期范围", padding="5")
        date_frame.pack(fill=tk.X, pady=5)
        
        ttk.Label(date_frame, text="开始日期 (YYYY-MM-DD):").grid(row=0, column=0, padx=5, pady=2)
        self.start_date_var = tk.StringVar()
        ttk.Entry(date_frame, textvariable=self.start_date_var, width=12).grid(row=0, column=1, padx=5, pady=2)
        
        ttk.Label(date_frame, text="结束日期 (YYYY-MM-DD):").grid(row=0, column=2, padx=5, pady=2)
        self.end_date_var = tk.StringVar()
        ttk.Entry(date_frame, textvariable=self.end_date_var, width=12).grid(row=0, column=3, padx=5, pady=2)
        
        ttk.Label(date_frame, text="注: 留空则使用数据全量范围").grid(row=1, column=0, columnspan=4, padx=5, pady=1, sticky=tk.W)
        
        # 文件编码选项
        encoding_frame = ttk.LabelFrame(control_frame, text="文件编码选项", padding="5")
        encoding_frame.pack(fill=tk.X, pady=5)
        
        ttk.Label(encoding_frame, text="文件编码:").grid(row=0, column=0, padx=5, pady=2)
        self.encoding_var = tk.StringVar(value="自动检测")
        encoding_combo = ttk.Combobox(encoding_frame, textvariable=self.encoding_var, 
                                      values=["自动检测", "utf-8", "gbk", "gb2312", "utf-16"],
                                      width=15)
        encoding_combo.grid(row=0, column=1, padx=5, pady=2)
        
        # 日期格式选项
        date_format_frame = ttk.LabelFrame(control_frame, text="数据日期格式", padding="5")
        date_format_frame.pack(fill=tk.X, pady=5)
        
        ttk.Label(date_format_frame, text="数据日期格式:").grid(row=0, column=0, padx=5, pady=2)
        self.date_format_var = tk.StringVar(value="YYYY-MM-DD")
        date_format_combo = ttk.Combobox(date_format_frame, textvariable=self.date_format_var, 
                                        values=["YYYY-MM-DD", "YYYY/MM/DD", "YYYYMMDD", "YYYY.MM.DD"],
                                        width=15)
        date_format_combo.grid(row=0, column=1, padx=5, pady=2)
        
        # 视图模式选项
        view_mode_frame = ttk.LabelFrame(control_frame, text="视图模式", padding="5")
        view_mode_frame.pack(fill=tk.X, pady=5)
        
        self.view_mode_var = tk.StringVar(value="增量")
        ttk.Radiobutton(view_mode_frame, text="净空单增量走势", variable=self.view_mode_var, value="增量").grid(row=0, column=0, padx=5, pady=2)
        ttk.Radiobutton(view_mode_frame, text="净空单实际数据走势", variable=self.view_mode_var, value="实际").grid(row=0, column=1, padx=5, pady=2)
        ttk.Label(view_mode_frame, text="选择显示净空单的走势类型").grid(row=0, column=2, padx=5, pady=2)
        
        # 分析选项
        ttk.Label(control_frame, text="分析选项:").pack(anchor=tk.W, pady=10)
        
        self.contract_vars = {}
        for contract in self.contract_types:
            var = tk.BooleanVar(value=True)
            ttk.Checkbutton(control_frame, text=f"{contract} ({self.index_mapping[contract]})", variable=var).pack(anchor=tk.W, pady=2)
            self.contract_vars[contract] = var
        
        # 滞后分析选项
        lag_frame = ttk.LabelFrame(control_frame, text="滞后分析选项", padding="5")
        lag_frame.pack(fill=tk.X, pady=5)
        
        ttk.Label(lag_frame, text="净空单数据滞后天数:").grid(row=0, column=0, padx=5, pady=2)
        self.lag_days_var = tk.StringVar(value="0")
        lag_days_combo = ttk.Combobox(lag_frame, textvariable=self.lag_days_var, 
                                      values=["0", "1", "2", "3"],
                                      width=5)
        lag_days_combo.grid(row=0, column=1, padx=5, pady=2)
        ttk.Label(lag_frame, text="0=不滞后，1=滞后1天，以此类推").grid(row=0, column=2, padx=5, pady=2)
        
        # 获取并保存指数数据按钮
        ttk.Button(control_frame, text="获取并保存指数数据", command=self.fetch_and_save_index_data).pack(pady=5)
        
        # 执行按钮
        ttk.Button(control_frame, text="执行分析", command=self.run_analysis_thread).pack(pady=20)
        
        # 日志区域
        ttk.Label(control_frame, text="操作日志:").pack(anchor=tk.W, pady=10)
        self.log_text = scrolledtext.ScrolledText(control_frame, width=40, height=15)
        self.log_text.pack(fill=tk.BOTH, expand=True)
        
        # 右侧结果展示面板
        results_frame = ttk.LabelFrame(main_frame, text="分析结果", padding="10")
        results_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 创建选项卡控件
        self.tab_control = ttk.Notebook(results_frame)
        self.tab_control.pack(fill=tk.BOTH, expand=True)
        
        # 为每个合约类型创建选项卡
        self.contract_tabs = {}
        for contract in self.contract_types:
            tab = ttk.Frame(self.tab_control)
            self.tab_control.add(tab, text=f"{contract}分析")
            self.contract_tabs[contract] = tab
        
        # 汇总结果选项卡
        self.summary_tab = ttk.Frame(self.tab_control)
        self.tab_control.add(self.summary_tab, text="汇总结果")
        
        # 滞后分析结果选项卡
        self.lag_analysis_tab = ttk.Frame(self.tab_control)
        self.tab_control.add(self.lag_analysis_tab, text="滞后分析对比")
    
    def browse_futures_file(self):
        """浏览并选择期货数据文件"""
        file_path = filedialog.askopenfilename(
            title="选择期货净空单数据文件",
            filetypes=[("CSV文件", "*.csv"), ("所有文件", "*.*")]
        )
        if file_path:
            self.futures_file_var.set(file_path)
            self.log(f"已选择文件: {file_path}")
    
    def log(self, message):
        """添加日志信息"""
        self.log_text.insert(tk.END, f"{message}\n")
        self.log_text.see(tk.END)
        self.root.update_idletasks()
    
    def run_analysis_thread(self):
        """在单独线程中运行分析，避免界面卡顿"""
        if not self.futures_file_var.get():
            messagebox.showerror("错误", "请先选择期货净空单数据文件")
            return
        
        # 禁用按钮防止重复点击
        threading.Thread(target=self.run_analysis, daemon=True).start()
    
    def run_analysis(self):
        """执行数据分析"""
        try:
            # 重置结果
            self.analysis_results = {}
            
            # 加载期货数据
            self.log("正在加载期货数据...")
            self.futures_data = self.load_data(self.futures_file_var.get())
            
            if self.futures_data is None:
                self.log("无法加载期货数据，请检查文件格式")
                return
            
            # 获取用户指定的日期范围
            user_start_date = self.start_date_var.get().strip()
            user_end_date = self.end_date_var.get().strip()
            
            # 转换用户输入的日期格式为标准格式 (YYYY-MM-DD)
            start_date = self._parse_date(user_start_date)
            end_date = self._parse_date(user_end_date)
            
            # 确定期货数据的日期范围
            try:
                # 使用指定的日期格式解析数据中的日期
                date_format = self.get_date_format()
                self.futures_data['日期'] = pd.to_datetime(self.futures_data['日期'], format=date_format)
                data_min_date = self.futures_data['日期'].min().strftime('%Y-%m-%d')
                data_max_date = self.futures_data['日期'].max().strftime('%Y-%m-%d')
                
                # 确定最终使用的分析日期范围
                final_start = start_date if start_date else data_min_date
                final_end = end_date if end_date else data_max_date
                
                # 转换为datetime对象以便比较
                final_start_dt = pd.to_datetime(final_start)
                final_end_dt = pd.to_datetime(final_end)
                
                # 确保开始日期不晚于结束日期
                if final_start_dt > final_end_dt:
                    self.log(f"警告: 开始日期 {final_start} 晚于结束日期 {final_end}，已交换顺序")
                    final_start, final_end = final_end, final_start
                    final_start_dt, final_end_dt = final_end_dt, final_start_dt
                
                # 确保日期范围在数据范围内
                data_min_dt = pd.to_datetime(data_min_date)
                data_max_dt = pd.to_datetime(data_max_date)
                
                if final_start_dt < data_min_dt:
                    self.log(f"警告: 开始日期 {final_start} 早于数据最早日期 {data_min_date}，已调整为 {data_min_date}")
                    final_start = data_min_date
                    final_start_dt = data_min_dt
                
                if final_end_dt > data_max_dt:
                    self.log(f"警告: 结束日期 {final_end} 晚于数据最晚日期 {data_max_date}，已调整为 {data_max_date}")
                    final_end = data_max_date
                    final_end_dt = data_max_dt
                
                self.log(f"期货数据日期范围: {data_min_date} 至 {data_max_date}")
                self.log(f"使用分析日期范围: {final_start} 至 {final_end}")
                
                # 筛选期货数据
                self.futures_data = self.futures_data[
                    (self.futures_data['日期'] >= final_start_dt) & 
                    (self.futures_data['日期'] <= final_end_dt)
                ]
                
                self.log(f"筛选后期货数据: {len(self.futures_data)} 行")
                
            except Exception as e:
                self.log(f"日期解析或筛选错误: {str(e)}")
                self.log("使用未筛选的期货数据")
        
        except Exception as e:
            self.log(f"分析准备阶段出错: {str(e)}")
            messagebox.showerror("错误", f"分析准备阶段出错: {str(e)}")
            return
        
        try:
            # 获取用户指定的滞后天数
            try:
                lag_days = int(self.lag_days_var.get())
                if lag_days < 0 or lag_days > 3:
                    lag_days = 0
                    self.log("警告: 滞后天数应在0-3之间，已设为0")
                self.log(f"使用净空单数据滞后天数: {lag_days}")
            except ValueError:
                lag_days = 0
                self.log("警告: 滞后天数无效，已设为0")
            
            # 分析选中的合约
            selected_contracts = [contract for contract, var in self.contract_vars.items() if var.get()]
            if not selected_contracts:
                self.log("请至少选择一个合约类型")
                return
            
            # 执行常规分析
            for contract in selected_contracts:
                self.log(f"\n正在分析 {contract} 期货数据（滞后{lag_days}天）...")
                self.analyze_contract(contract, lag_days)
            
            # 如果选择了滞后分析，执行多日滞后对比分析
            if lag_days > 0:
                self.perform_lag_analysis_comparison(selected_contracts)
            
            # 显示汇总结果
            self.display_summary_results()
            
            self.log("\n分析完成！")
            
        except Exception as e:
            self.log(f"分析过程中出错: {str(e)}")
            messagebox.showerror("错误", f"分析过程中出错: {str(e)}")
    
    def _parse_date(self, date_str):
        """解析用户输入的日期，返回标准格式 (YYYY-MM-DD) 或None"""
        if not date_str:
            return None
        
        try:
            # 尝试按用户输入的格式解析
            date_format = self.date_format_var.get()
            format_map = {
                "YYYY-MM-DD": "%Y-%m-%d",
                "YYYY/MM/DD": "%Y/%m/%d",
                "YYYYMMDD": "%Y%m%d",
                "YYYY.MM.DD": "%Y.%m.%d"
            }
            date_obj = pd.to_datetime(date_str, format=format_map.get(date_format, "%Y-%m-%d"))
            return date_obj.strftime('%Y-%m-%d')
        except Exception as e:
            self.log(f"日期解析错误: {date_str} - {str(e)}")
            messagebox.showerror("日期格式错误", f"无法解析日期 '{date_str}'\n请使用格式: {self.date_format_var.get()}")
            return None
    
    def get_date_format(self):
        """获取数据日期格式字符串"""
        format_map = {
            "YYYY-MM-DD": "%Y-%m-%d",
            "YYYY/MM/DD": "%Y/%m/%d",
            "YYYYMMDD": "%Y%m%d",
            "YYYY.MM.DD": "%Y.%m.%d"
        }
        return format_map.get(self.date_format_var.get(), "%Y-%m-%d")
    
    def detect_file_encoding(self, file_path):
        """检测文件编码"""
        try:
            with open(file_path, 'rb') as f:
                raw_data = f.read(10240)  # 读取前10KB数据进行编码检测
            
            result = chardet.detect(raw_data)
            encoding = result['encoding']
            confidence = result['confidence']
            
            self.log(f"检测到文件编码: {encoding}，置信度: {confidence:.2f}")
            return encoding
        except Exception as e:
            self.log(f"编码检测失败: {str(e)}")
            return 'utf-8'  # 默认使用utf-8
    
    def load_data(self, file_path):
        """加载数据文件"""
        try:
            if not os.path.exists(file_path):
                self.log(f"文件不存在: {file_path}")
                return None
            
            # 获取用户选择的编码或自动检测
            encoding = self.encoding_var.get()
            if encoding == "自动检测":
                encoding = self.detect_file_encoding(file_path)
            
            # 尝试自动检测分隔符
            with open(file_path, 'r', encoding=encoding) as f:
                first_line = f.readline().strip()
                if '\t' in first_line:
                    sep = '\t'
                    self.log("检测到文件使用制表符分隔")
                elif ';' in first_line:
                    sep = ';'
                    self.log("检测到文件使用分号分隔")
                else:
                    sep = ','
                    self.log("检测到文件使用逗号分隔")
            
            # 读取CSV文件
            data = pd.read_csv(file_path, sep=sep, encoding=encoding)
            self.log(f"成功加载数据: {file_path}")
            self.log(f"数据包含 {len(data)} 行，{len(data.columns)} 列")
            self.log(f"列名: {', '.join(data.columns.tolist())}")
            
            return data
        except UnicodeDecodeError as e:
            self.log(f"编码错误: 无法使用 {encoding} 编码读取文件")
            self.log(f"错误详情: {str(e)}")
            self.log("请尝试手动选择其他编码")
            return None
        except Exception as e:
            self.log(f"加载数据时出错: {str(e)}")
            return None
    
    def get_index_data_from_api(self, contract_type, start_date=None, end_date=None):
        """通过akshare API获取指数数据"""
        self.log(f"从API获取{contract_type}({self.index_mapping[contract_type]})指数数据...")
        
        # 映射期货品种到对应的指数代码
        index_code_mapping = {
            'IF': '000300',  # 沪深300指数
            'IC': '000905',  # 中证500指数
            'IM': '000852',  # 中证1000指数
            'IH': '000016'   # 上证50指数
        }
        
        if contract_type not in index_code_mapping:
            self.log(f"不支持的期货品种: {contract_type}")
            return None
        
        index_code = index_code_mapping[contract_type]
        
        try:
            self.log("正在请求API数据...")
            
            # 尝试获取指数数据
            try:
                # 先尝试新版API
                index_data = ak.stock_zh_index_daily(symbol=f"sh{index_code}")
                self.log(f"成功获取{contract_type}指数数据（新版API）")
            except Exception as e:
                # 尝试旧版API
                self.log(f"新版API失败，尝试旧版API: {str(e)}")
                index_data = ak.stock_zh_index_daily_em(symbol=index_code)
                self.log(f"成功获取{contract_type}指数数据（旧版API）")
            
            self.log(f"API返回数据: {len(index_data)} 行，{len(index_data.columns)} 列")
            self.log(f"API返回列名: {', '.join(index_data.columns.tolist())}")
            
            # 数据处理逻辑
            if len(index_data.columns) >= 5:
                # 假设前5列是日期、开盘价、最高价、最低价、收盘价
                index_data = index_data.iloc[:, :5].copy()
                index_data.columns = ['日期', '开盘价', '最高价', '最低价', '收盘价']
            else:
                raise ValueError(f"API返回列数不足: {len(index_data.columns)} 列")
            
            # 确保日期列是日期类型
            index_data['日期'] = pd.to_datetime(index_data['日期'])
            
            # 筛选日期范围
            if start_date:
                index_data = index_data[index_data['日期'] >= start_date]
            if end_date:
                index_data = index_data[index_data['日期'] <= end_date]
            
            # 为滞后分析扩展日期范围
            if start_date:
                extend_days = pd.Timedelta(days=4)  # 覆盖0-3天的滞后
                extended_start = pd.to_datetime(start_date) - extend_days
                try:
                    extended_data = ak.stock_zh_index_daily(symbol=f"sh{index_code}")
                    extended_data['日期'] = pd.to_datetime(extended_data['日期'])
                    extended_data = extended_data[
                        (extended_data['日期'] >= extended_start) & 
                        (extended_data['日期'] <= end_date)
                    ]
                    if not extended_data.empty:
                        index_data = extended_data
                        self.log(f"为滞后分析扩展日期范围至: {extended_start.strftime('%Y-%m-%d')}")
                except Exception as e:
                    self.log(f"扩展日期范围失败: {str(e)}")
            
            self.log(f"筛选后指数数据: {len(index_data)} 行")
            
            return index_data
        except Exception as e:
            self.log(f"获取{contract_type}指数数据时出错: {str(e)}")
            import traceback
            self.log(f"详细错误堆栈:\n{traceback.format_exc()}")
            return None
    
    def save_index_data(self, index_data, contract_type):
        """保存指数数据到文件"""
        if index_data is None or index_data.empty:
            self.log(f"无法保存{contract_type}指数数据：数据为空")
            return False
        
        try:
            # 确保保存目录存在
            save_dir = os.path.dirname(self.futures_file_var.get())
            if not os.path.exists(save_dir):
                os.makedirs(save_dir)
            
            # 保存到文件
            file_name = os.path.join(save_dir, f"{contract_type}_指数数据.csv")
            index_data.to_csv(file_name, index=False)
            self.log(f"已成功将{contract_type}指数数据保存至: {file_name}")
            return True
        except Exception as e:
            self.log(f"保存{contract_type}指数数据时出错: {str(e)}")
            return False
    
    def fetch_and_save_index_data(self):
        """获取并保存指数数据"""
        if not self.futures_file_var.get():
            messagebox.showerror("错误", "请先选择期货净空单数据文件")
            return
        
        # 获取用户指定的日期范围
        user_start_date = self.start_date_var.get().strip()
        user_end_date = self.end_date_var.get().strip()
        
        # 解析日期
        start_date = self._parse_date(user_start_date)
        end_date = self._parse_date(user_end_date)
        
        # 获取选中的合约
        selected_contracts = [contract for contract, var in self.contract_vars.items() if var.get()]
        if not selected_contracts:
            self.log("请至少选择一个合约类型")
            return
        
        self.log("开始获取并保存指数数据...")
        
        # 在单独线程中执行，避免界面卡顿
        threading.Thread(target=self._fetch_and_save_index_data_thread, 
                         args=(selected_contracts, start_date, end_date), 
                         daemon=True).start()
    
    def _fetch_and_save_index_data_thread(self, contracts, start_date, end_date):
        """在线程中执行获取并保存指数数据的操作"""
        success_count = 0
        for contract in contracts:
            self.log(f"\n正在获取{contract}({self.index_mapping[contract]})指数数据...")
            index_data = self.get_index_data_from_api(contract, start_date, end_date)
            
            if index_data is not None and not index_data.empty:
                if self.save_index_data(index_data, contract):
                    success_count += 1
                else:
                    self.log(f"保存{contract}指数数据失败")
            else:
                self.log(f"获取{contract}指数数据失败或数据为空")
        
        self.log(f"\n指数数据获取完成: {success_count} 个成功, {len(contracts) - success_count} 个失败")
        messagebox.showinfo("完成", f"指数数据获取完成: {success_count} 个成功, {len(contracts) - success_count} 个失败")
    
    def calculate_net_short_increase(self, data, contract_type):
        """计算特定期货合约的净空单增量（百分比）"""
        # 提取特定期货的净空单数据
        contract_data = data[['日期', contract_type]].copy()
        contract_data.columns = ['日期', '净空单']
        
        # 计算净空单增量（百分比）
        contract_data['净空单增量(%)'] = contract_data['净空单'].pct_change() * 100
        
        return contract_data
    
    def filter_index_data_by_futures_dates(self, futures_data, index_data):
        """根据期货数据的日期筛选指数数据"""
        # 获取期货数据中的所有日期
        futures_dates = set(futures_data['日期'].dt.strftime('%Y-%m-%d'))
        
        # 筛选指数数据，只保留期货数据中存在的日期
        filtered_index_data = index_data[
            index_data['日期'].dt.strftime('%Y-%m-%d').isin(futures_dates)
        ].copy()
        
        # 计算匹配率
        matched_ratio = len(filtered_index_data) / len(index_data) if len(index_data) > 0 else 0
        
        self.log(f"指数数据共 {len(index_data)} 行，匹配期货数据日期的有 {len(filtered_index_data)} 行")
        self.log(f"日期匹配率: {matched_ratio:.2%}")
        
        if len(filtered_index_data) < len(index_data):
            self.log("警告: 部分指数数据日期在期货数据中不存在，已被过滤")
        
        return filtered_index_data
    
    def lag_futures_data(self, futures_data, lag_days):
        """对期货数据进行滞后处理"""
        if lag_days <= 0:
            return futures_data.copy()
        
        self.log(f"对期货数据进行{lag_days}天滞后处理...")
        
        # 创建滞后的期货数据副本
        lagged_data = futures_data.copy()
        
        # 将净空单增量数据向后移动lag_days天
        lagged_data['净空单增量(%)'] = lagged_data['净空单增量(%)'].shift(lag_days)
        
        # 移除因滞后产生的NaN值
        original_count = len(lagged_data)
        lagged_data = lagged_data.dropna(subset=['净空单增量(%)'])
        removed_count = original_count - len(lagged_data)
        
        self.log(f"因滞后处理移除了 {removed_count} 行数据")
        
        return lagged_data
    
    def analyze_contract(self, contract_type, lag_days=0):
        """分析单个合约"""
        try:
            # 计算净空单增量
            contract_results = self.calculate_net_short_increase(self.futures_data, contract_type)
            
            # 尝试加载指数数据
            index_file = os.path.join(os.path.dirname(self.futures_file_var.get()), 
                                     f"{contract_type}_指数数据.csv")
            index_data = self.load_data(index_file)
            
            # 如果指数数据不存在，从API获取
            if index_data is None:
                self.log(f"未找到{contract_type}指数数据文件，将从API获取...")
                # 使用当前分析的日期范围获取指数数据
                start_date = self.start_date_var.get().strip()
                end_date = self.end_date_var.get().strip()
                index_data = self.get_index_data_from_api(contract_type, start_date, end_date)
                if index_data is None:
                    self.log(f"跳过{contract_type}分析：无法获取指数数据")
                    return
                
                # 保存获取的指数数据
                if not self.save_index_data(index_data, contract_type):
                    self.log(f"警告: 无法保存{contract_type}指数数据，将继续分析")
            
            # 确保指数数据的日期格式一致
            index_data['日期'] = pd.to_datetime(index_data['日期'])
            
            # 以期货数据的日期为准，筛选指数数据
            self.log(f"\n开始根据{contract_type}期货数据的日期筛选指数数据...")
            filtered_index_data = self.filter_index_data_by_futures_dates(contract_results, index_data)
            
            if len(filtered_index_data) == 0:
                self.log(f"错误: 筛选后{contract_type}指数数据为空，无法进行分析")
                return
            
            # 对期货数据进行滞后处理
            if lag_days > 0:
                contract_results = self.lag_futures_data(contract_results, lag_days)
            
            # 确保滞后处理后还有足够的数据
            if len(contract_results) < 10:
                self.log(f"错误: 滞后处理后{contract_type}期货数据不足，无法进行分析")
                return
            
            # 重新筛选指数数据，确保与滞后的期货数据匹配
            filtered_index_data = self.filter_index_data_by_futures_dates(contract_results, filtered_index_data)
            
            if len(filtered_index_data) < 10:
                self.log(f"错误: 滞后处理后{contract_type}匹配的指数数据不足，无法进行分析")
                return
            
            # 分析相关性
            correlation = self.analyze_correlation(contract_results, filtered_index_data, contract_type, lag_days)
            self.analysis_results[(contract_type, lag_days)] = correlation
            
            # 合并数据用于可视化
            viz_data = pd.merge(contract_results, filtered_index_data, on='日期', how='inner')
            viz_data['指数涨跌幅(%)'] = viz_data['收盘价'].pct_change() * 100
            
            # 检查合并后的数据量
            if len(viz_data) < 10:
                self.log(f"警告: {contract_type}的合并数据量较少 ({len(viz_data)} 行)，结果可能不可靠")
            
            # 可视化结果
            self.display_contract_results(contract_type, viz_data, correlation, lag_days)
            
            self.log(f"{contract_type}期货分析完成（滞后{lag_days}天）: {correlation['结论']}")
            
        except Exception as e:
            self.log(f"分析{contract_type}期货时出错: {str(e)}")
    
    def analyze_correlation(self, futures_data, index_data, contract_type, lag_days=0):
        """分析期货净空单增量与指数涨跌的关系"""
        # 合并期货和指数数据
        merged_data = pd.merge(futures_data, index_data, on='日期', how='inner')
        
        # 计算指数涨跌幅
        merged_data['指数涨跌幅(%)'] = merged_data['收盘价'].pct_change() * 100
        
        # 计算相关系数和p值
        valid_data = merged_data.dropna(subset=['净空单增量(%)', '指数涨跌幅(%)'])
        if len(valid_data) < 2:
            return {
                '合约类型': contract_type,
                '滞后天数': lag_days,
                '相关系数': np.nan,
                'p值': np.nan,
                '数据点数': 0,
                '结论': '数据不足，无法计算相关性'
            }
        
        corr, p_value = pearsonr(valid_data['净空单增量(%)'], valid_data['指数涨跌幅(%)'])
        
        # 确定相关性方向和强度
        if np.abs(corr) < 0.1:
            strength = "极弱"
        elif np.abs(corr) < 0.3:
            strength = "弱"
        elif np.abs(corr) < 0.5:
            strength = "中等"
        else:
            strength = "强"
        
        direction = "正" if corr > 0 else "负"
        
        return {
            '合约类型': contract_type,
            '滞后天数': lag_days,
            '相关系数': corr,
            'p值': p_value,
            '数据点数': len(valid_data),
            '相关性强度': strength,
            '相关性方向': direction,
            '结论': f"{direction}{strength}相关" if p_value < 0.05 else "不显著相关"
        }
    
    def perform_lag_analysis_comparison(self, contracts):
        """执行多日滞后分析对比"""
        self.log("\n开始执行滞后分析对比...")
        
        # 为每个合约执行0-3天的滞后分析
        all_lag_results = {}
        
        # 获取用户指定的日期范围
        start_date = self.start_date_var.get().strip()
        end_date = self.end_date_var.get().strip()
        
        for contract in contracts:
            contract_lag_results = []
            
            for lag in range(4):  # 0,1,2,3天滞后
                self.log(f"\n分析 {contract} 期货数据（滞后{lag}天）...")
                
                # 计算净空单增量
                contract_results = self.calculate_net_short_increase(self.futures_data, contract)
                
                # 加载指数数据
                index_file = os.path.join(os.path.dirname(self.futures_file_var.get()), 
                                         f"{contract}_指数数据.csv")
                index_data = self.load_data(index_file)
                
                if index_data is None:
                    self.log(f"未找到{contract}指数数据文件，跳过滞后{lag}天分析")
                    continue
                
                # 确保指数数据的日期格式一致
                index_data['日期'] = pd.to_datetime(index_data['日期'])
                
                # 筛选指数数据
                filtered_index_data = self.filter_index_data_by_futures_dates(contract_results, index_data)
                
                if len(filtered_index_data) == 0:
                    self.log(f"错误: 筛选后{contract}指数数据为空，跳过滞后{lag}天分析")
                    continue
                
                # 对期货数据进行滞后处理
                if lag > 0:
                    contract_results = self.lag_futures_data(contract_results, lag)
                
                # 确保滞后处理后还有足够的数据
                if len(contract_results) < 10:
                    self.log(f"错误: 滞后{lag}天后{contract}期货数据不足，跳过此滞后分析")
                    continue
                
                # 重新筛选指数数据，确保与滞后的期货数据匹配
                filtered_index_data = self.filter_index_data_by_futures_dates(contract_results, filtered_index_data)
                
                if len(filtered_index_data) < 10:
                    self.log(f"错误: 滞后{lag}天后{contract}匹配的指数数据不足，跳过此滞后分析")
                    continue
                
                # 分析相关性
                correlation = self.analyze_correlation(contract_results, filtered_index_data, contract, lag)
                contract_lag_results.append(correlation)
                
                self.log(f"{contract}期货（滞后{lag}天）分析完成: {correlation['结论']}")
            
            if contract_lag_results:
                all_lag_results[contract] = contract_lag_results
        
        # 显示滞后分析结果
        self.display_lag_analysis_results(all_lag_results)
    
    def display_lag_analysis_results(self, all_lag_results):
        """显示滞后分析结果"""
        # 清除滞后分析选项卡中的现有内容
        for widget in self.lag_analysis_tab.winfo_children():
            widget.destroy()
        
        # 创建结果展示框架
        frame = ttk.Frame(self.lag_analysis_tab, padding="10")
        frame.pack(fill=tk.BOTH, expand=True)
        
        # 为每个合约创建图表
        for i, (contract, results) in enumerate(all_lag_results.items()):
            if not results:
                continue
            
            # 创建合约的结果框架
            contract_frame = ttk.LabelFrame(frame, text=f"{contract}期货滞后分析结果", padding="10")
            contract_frame.pack(fill=tk.X, pady=5)
            
            # 提取数据用于绘图
            lags = [r['滞后天数'] for r in results]
            correlations = [r['相关系数'] for r in results]
            p_values = [r['p值'] for r in results]
            
            # 创建图表
            fig = Figure(figsize=(10, 4), dpi=100)
            
            # 相关系数子图
            ax1 = fig.add_subplot(121)
            ax1.bar(lags, correlations, color='skyblue', width=0.6)
            ax1.set_title('相关系数')
            ax1.set_xlabel('滞后天数')
            ax1.set_ylabel('相关系数值')
            ax1.set_xticks(lags)
            ax1.set_ylim(-1, 1)
            ax1.axhline(y=0, color='black', linestyle='-', alpha=0.3)
            
            # 添加相关系数数值标签
            for i, v in enumerate(correlations):
                ax1.text(lags[i], v + 0.05, f"{v:.2f}", ha='center', fontweight='bold')
            
            # p值子图
            ax2 = fig.add_subplot(122)
            ax2.bar(lags, p_values, color='lightgreen', width=0.6)
            ax2.set_title('p值')
            ax2.set_xlabel('滞后天数')
            ax2.set_ylabel('p值')
            ax2.set_xticks(lags)
            ax2.set_ylim(0, 1)
            ax2.axhline(y=0.05, color='red', linestyle='--', alpha=0.5, label='显著性水平(0.05)')
            ax2.legend()
            
            # 添加p值数值标签
            for i, v in enumerate(p_values):
                ax2.text(lags[i], v + 0.05, f"{v:.3f}", ha='center', fontweight='bold')
            
            # 在图表下方添加表格展示详细数据
            table_frame = ttk.Frame(contract_frame)
            table_frame.pack(fill=tk.X, pady=10)
            
            columns = ('滞后天数', '相关系数', 'p值', '数据点数', '结论')
            tree = ttk.Treeview(table_frame, columns=columns, show='headings')
            
            for col in columns:
                tree.heading(col, text=col)
                tree.column(col, width=120, anchor=tk.CENTER)
            
            for result in results:
                tree.insert('', tk.END, values=(
                    result['滞后天数'],
                    f"{result['相关系数']:.4f}",
                    f"{result['p值']:.4f}",
                    result['数据点数'],
                    result['结论']
                ))
            
            tree.pack(fill=tk.X)
            
            # 将图表添加到GUI
            canvas = FigureCanvasTkAgg(fig, master=contract_frame)
            canvas.draw()
            canvas.get_tk_widget().pack(fill=tk.X, pady=5)
            
            # 添加最佳滞后天数提示
            best_result = max(results, key=lambda x: abs(x['相关系数']) if x['p值'] < 0.05 else -float('inf'))
            if best_result['p值'] < 0.05:
                ttk.Label(contract_frame, 
                        text=f"最佳预测滞后天数: {best_result['滞后天数']}天 ({best_result['相关性方向']}{best_result['相关性强度']}相关)",
                        font=('SimHei', 10, 'bold')).pack(pady=5, anchor=tk.W)
            else:
                ttk.Label(contract_frame, 
                        text="未发现显著相关性",
                        font=('SimHei', 10, 'bold')).pack(pady=5, anchor=tk.W)
                
    def display_summary_results(self):
        """显示汇总结果"""
        # 清除汇总选项卡中的现有内容
        for widget in self.summary_tab.winfo_children():
            widget.destroy()
        
        # 创建结果展示框架
        frame = ttk.Frame(self.summary_tab, padding="10")
        frame.pack(fill=tk.BOTH, expand=True)
        
        # 获取用户选择的滞后天数
        lag_days = int(self.lag_days_var.get())
        
        # 筛选当前选择滞后天数的分析结果
        current_results = [
            result for (contract, lag), result in self.analysis_results.items() 
            if lag == lag_days
        ]
        
        if not current_results:
            ttk.Label(frame, text="没有分析结果可供展示", font=('SimHei', 12)).pack(pady=20)
            return
        
        # 创建表格
        columns = ('合约类型', '相关系数', 'p值', '数据点数', '结论')
        tree = ttk.Treeview(frame, columns=columns, show='headings')
        
        for col in columns:
            tree.heading(col, text=col)
            tree.column(col, width=150, anchor=tk.CENTER)
        
        # 添加数据
        for result in current_results:
            tree.insert('', tk.END, values=(
                result['合约类型'],
                f"{result['相关系数']:.4f}",
                f"{result['p值']:.4f}",
                result['数据点数'],
                result['结论']
            ))
        
        tree.pack(fill=tk.BOTH, expand=True, pady=10)
        
        # 添加说明
        ttk.Label(frame, 
                text=f"注: 以上结果为期货净空单数据滞后{lag_days}天与指数涨跌幅的相关性分析",
                font=('SimHei', 10)).pack(pady=5, anchor=tk.W)
        
        # 分析总体特征
        significant_results = [r for r in current_results if r['p值'] < 0.05]
        positive_corr = [r for r in significant_results if r['相关系数'] > 0]
        negative_corr = [r for r in significant_results if r['相关系数'] < 0]
        
        ttk.Label(frame, text="", font=('SimHei', 12)).pack(pady=5)
        ttk.Label(frame, text="总体分析特征:", font=('SimHei', 12, 'bold')).pack(anchor=tk.W)
        ttk.Label(frame, text=f"显著相关合约数量: {len(significant_results)}/{len(current_results)}", font=('SimHei', 10)).pack(anchor=tk.W)
        ttk.Label(frame, text=f"正相关合约: {', '.join([r['合约类型'] for r in positive_corr])}", font=('SimHei', 10)).pack(anchor=tk.W)
        ttk.Label(frame, text=f"负相关合约: {', '.join([r['合约类型'] for r in negative_corr])}", font=('SimHei', 10)).pack(anchor=tk.W)

    def display_contract_results(self, contract_type, data, correlation, lag_days=0):
        """显示单个合约的分析结果"""
        # 清除合约选项卡中的现有内容
        contract_tab = self.contract_tabs[contract_type]
        for widget in contract_tab.winfo_children():
            widget.destroy()
        
        # 创建结果展示框架
        frame = ttk.Frame(contract_tab, padding="10")
        frame.pack(fill=tk.BOTH, expand=True)
        
        # 创建标题
        ttk.Label(frame, 
                text=f"{contract_type}期货净空单与{self.index_mapping[contract_type]}指数涨跌关系分析 (滞后{lag_days}天)",
                font=('SimHei', 14, 'bold')).pack(pady=10)
        
        # 显示相关性结果
        corr_frame = ttk.LabelFrame(frame, text="相关性分析结果", padding="10")
        corr_frame.pack(fill=tk.X, pady=5)
        
        ttk.Label(corr_frame, 
                text=f"相关系数: {correlation['相关系数']:.4f}，p值: {correlation['p值']:.4f}，数据点数: {correlation['数据点数']}",
                font=('SimHei', 10)).pack(anchor=tk.W)
        
        ttk.Label(corr_frame, 
                text=f"结论: {correlation['结论']}（{correlation['相关性方向']}{correlation['相关性强度']}相关）",
                font=('SimHei', 10, 'bold')).pack(anchor=tk.W)
        
        # 创建可交互的双Y轴图表
        fig = Figure(figsize=(12, 8), dpi=100)
        ax1 = fig.add_subplot(111)
        
        # 根据视图模式绘制不同数据
        view_mode = self.view_mode_var.get()
        
        if view_mode == "增量":
            # 绘制净空单增量百分比（左Y轴）
            ax1.plot(data['日期'], data['净空单增量(%)'], label='净空单增量(%)', color='blue', linewidth=1.5)
            ax1.set_ylabel('净空单增量(%)', color='blue')
        else:
            # 绘制净空单实际数据（左Y轴）
            ax1.plot(data['日期'], data['净空单'], label='净空单实际数据', color='blue', linewidth=1.5)
            ax1.set_ylabel('净空单实际值', color='blue')
        
        ax1.tick_params(axis='y', labelcolor='blue')
        ax1.axhline(y=0, color='black', linestyle='-', alpha=0.3, linewidth=1)
        
        # 指数涨跌幅绘制（右Y轴）
        ax2 = ax1.twinx()
        ax2.plot(data['日期'], data['指数涨跌幅(%)'], label='指数涨跌幅(%)', color='red', linewidth=1.5)
        ax2.set_ylabel('指数涨跌幅(%)', color='red')
        ax2.tick_params(axis='y', labelcolor='red')
        ax2.axhline(y=0, color='black', linestyle='-', alpha=0.3, linewidth=1)
        
        # 设置标题和图例
        fig.suptitle(f"{contract_type}期货净空单与{self.index_mapping[contract_type]}指数走势关系图", fontsize=14)
        ax1.set_xlabel('日期')
        
        # 合并两个图例
        lines1, labels1 = ax1.get_legend_handles_labels()
        lines2, labels2 = ax2.get_legend_handles_labels()
        ax2.legend(lines1 + lines2, labels1 + labels2, loc='upper right')
        
        # 添加视图模式说明
        ttk.Label(frame, text=f"当前视图模式: {'净空单增量走势' if view_mode == '增量' else '净空单实际数据走势'}").pack(pady=5, anchor=tk.W)
        
        # 将图表添加到GUI
        canvas = FigureCanvasTkAgg(fig, master=frame)
        canvas.draw()
        canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True, pady=10)
        
        # 添加导航工具栏
        toolbar = NavigationToolbar2Tk(canvas, frame)
        toolbar.update()
        
        # 显示最近10条数据
        data_display_frame = ttk.LabelFrame(frame, text="最近10条数据", padding="10")
        data_display_frame.pack(fill=tk.X, pady=5)
        
        # 提取最后10行数据
        recent_data = data.tail(10)
        
        if view_mode == "增量":
            # 显示增量百分比和指数涨跌幅
            display_cols = ['日期', '净空单增量(%)', '指数涨跌幅(%)']
            formatters = {'净空单增量(%)': lambda x: f"{x:.2f}%", '指数涨跌幅(%)': lambda x: f"{x:.2f}%"}
        else:
            # 显示实际净空单和指数收盘价
            recent_data['指数涨跌幅(%)'] = recent_data['指数涨跌幅(%)'].apply(lambda x: f"{x:.2f}%")
            display_cols = ['日期', '净空单', '指数涨跌幅(%)', '收盘价']
            formatters = None
        
        # 格式化数据为字符串
        data_text = recent_data[display_cols].to_string(index=False, formatters=formatters)
        
        # 创建文本框显示数据
        text_widget = scrolledtext.ScrolledText(data_display_frame, width=80, height=10, wrap=tk.WORD)
        text_widget.insert(tk.END, data_text)
        text_widget.configure(state='disabled')  # 设为只读
        text_widget.pack(fill=tk.BOTH, expand=True)

# 主程序入口
if __name__ == "__main__":
    root = tk.Tk()
    app = FuturesAnalysisApp(root)
    root.mainloop()
